package com.sangmo.fts.teacher.service;

import com.sangmo.boot.framework.cache.meta.Cache;
import com.sangmo.boot.framework.common.errors.ServiceException;
import com.sangmo.boot.framework.common.errors.StandardErrors;
import com.sangmo.boot.framework.common.session.UserSession;
import com.sangmo.boot.framework.plugin.dataview.crud.service.BaseViewService;
import com.sangmo.boot.framework.plugin.dataview.data.IDataViewRepo;
import com.sangmo.boot.framework.plugin.dataview.spi.jpa.NativeQueryBuilderFactory;
import com.sangmo.fts.clazz.model.Clazz;
import com.sangmo.fts.clazz.model.UserClazz;
import com.sangmo.fts.clazz.service.UserClazzEntityService;
import com.sangmo.fts.teacher.interfaces.ExaminationCreation;
import com.sangmo.fts.teacher.interfaces.ExaminationUpdate;
import com.sangmo.fts.teacher.model.Examination;
import com.sangmo.fts.teacher.model.ExaminationClazz;
import com.sangmo.fts.teacher.model.ScoreSetting;
import com.sangmo.fts.teacher.repo.ExaminationRepo;
import com.sangmo.fts.training.model.Training;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class ExaminationEntityService extends BaseViewService<Examination> {

    @Autowired
    private ExaminationRepo examinationRepo;

    @Autowired
    private UserClazzEntityService userClazzEntityService;

    @Autowired
    private ExaminationClazzEntityService examinationClazzEntityService;

    @Autowired
    private ScoreSettingService scoreSettingService;

    @Override
    protected IDataViewRepo<Examination> getRepo() {
        return examinationRepo;
    }

    @Cache(300)
    public Examination findOneCache(Long id) {
        return this.find(id);
    }

    @Override
    protected void onCreate(Examination entity, Object bo) {
        super.onCreate(entity, bo);
        ScoreSetting scoreSetting = scoreSettingService.findByUserId();
        if (null == scoreSetting) {
            throw new ServiceException(StandardErrors.CLIENT_ERROR.getStatus(), "error.scoreSetting.teacher.notExists");
        }
    }

    @Override
    protected void afterCreated(Examination entity, Object bo) {
        super.afterCreated(entity, bo);
        ExaminationCreation creation = (ExaminationCreation) bo;
        checkClazzIfNoAccess(creation.getClazzIds());
        for (Long clazzId : creation.getClazzIds()) {
            ExaminationClazz examinationClazz = new ExaminationClazz();
            examinationClazz.setExaminationId(entity.getId());
            examinationClazz.setClazzId(clazzId);
            examinationClazzEntityService.save(examinationClazz);
        }
    }

    @Override
    protected void afterUpdated(Examination entity, Object bo) {
        super.afterUpdated(entity, bo);
        ExaminationUpdate update = (ExaminationUpdate) bo;
        checkClazzIfNoAccess(update.getClazzIds());
        examinationClazzEntityService.deleteByExaminationId(entity.getId());
        for (Long clazzId : update.getClazzIds()) {
            ExaminationClazz examinationClazz = new ExaminationClazz();
            examinationClazz.setExaminationId(entity.getId());
            examinationClazz.setClazzId(clazzId);
            examinationClazzEntityService.save(examinationClazz);
        }
    }

    @Override
    protected void onUpdate(Examination entity, Object bo) {
        super.onUpdate(entity, bo);
        long currentTime = System.currentTimeMillis();
        if (currentTime >= entity.getStartTime().getTime()) {
            throw new ServiceException(StandardErrors.CLIENT_ERROR.getStatus(), "error.examination.update.notallowed");
        }
    }

    private void checkClazzIfNoAccess(List<Long> clazzIds) {
        List<UserClazz> userClazzes = userClazzEntityService.findByUserId((Long) UserSession.getUserInterface().getId());
        List<Long> clazzIdsInDb = userClazzes.stream().map(UserClazz::getClazzId).collect(Collectors.toList());
        if (!clazzIdsInDb.containsAll(clazzIds)) {
            throw new ServiceException(StandardErrors.CLIENT_ERROR.getStatus(), "error.examination.clazz.noaccess");
        }
    }

    @Override
    protected void onDelete(Examination entity) {
        super.onDelete(entity);
        long currentTime = System.currentTimeMillis();
        if (entity.getStartTime().getTime() <= currentTime && currentTime <= entity.getEndTime().getTime()) {
            throw new ServiceException(StandardErrors.CLIENT_ERROR.getStatus(), "error.examination.delete.notallowed");
        }
    }

    protected Collection<Examination> findPendingExam() {
        Date nowDate = new Date();
        Collection<Examination> examinations = NativeQueryBuilderFactory.create()
                .putAlias("a", Examination.class)
                .selectForm("SELECT a.* from examination a ")
                .where(" a.state = 'PENDING' AND a.end_Time < :now")
                .putVariable("now", nowDate)
                .setPage(0, 5)
                .transform(Examination.class)
                .buildPage().getRows();
        return examinations;
    }

}
